package com.djdg.foodies.admin.base.interceptor;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 请求日志
 * @Auther Demon
 * @Date 2017/12/15 15:57 星期五
 */
@Component
@Order(5)
@WebFilter(filterName = "logFilter", urlPatterns = "/*")
public class RequestLogFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(RequestLogFilter.class);

    private FilterConfig filterConfig = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper;

        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String contentType = httpServletRequest.getHeader("content-type");
            if(StringUtils.isNotBlank(contentType) && contentType.contains("form-data")){
                logger.info("开始文件上传....");
                chain.doFilter(request,response);
                return;
            }
            // 过滤swagger文档请求
            String uri = httpServletRequest.getRequestURI().substring(5);
            if(uri.startsWith("swagger") || uri.startsWith("webjars") || uri.startsWith("v2/api-docs")) {
                chain.doFilter(request,response);
                return;
            }
            requestWrapper = new BufferHttpServletRequestWrapper(httpServletRequest);
        } else {
            chain.doFilter(request,response);
            return;
        }
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        InputStream reader = requestWrapper.getInputStream();
        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(100);
        int i ;
        byte [] b = new byte[100];
        while((i = reader.read(b))!= -1){
            byteOutput.write(b, 0, i);
        }

        Enumeration<String> headerNames =  servletRequest.getHeaderNames();
        Map<String, String> headers = new HashMap<>();
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            headers.put(name, servletRequest.getHeader(name));
        }
        logger.info("**************************Request Info**************************");
        logger.info("Request {}  {}", servletRequest.getMethod(), servletRequest.getRequestURL());
        logger.info("Request MediaType:"+ servletRequest.getContentType());
        logger.info("Request Headers: "+ headers);
        if (HttpMethod.GET.name().equals(servletRequest.getMethod())) {
            String arg = JSONObject.toJSONString(servletRequest.getParameterMap());
            logger.info("Request Content:" + arg);
        } else {
            String arg = new String(byteOutput.toByteArray(), "utf-8");
            logger.info("Request Content:" + arg);
        }
        chain.doFilter(requestWrapper, response);
    }

    @Override
    public void destroy() {

    }


    class BufferHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private final byte[] body;
        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request The request to wrap
         * @throws IllegalArgumentException if the request is null
         */
        BufferHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            InputStream is = request.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buff = new byte[ 1024 ];
            int read;
            while( ( read = is.read( buff ) ) > 0 ) {
                bos.write( buff, 0, read );
            }
            body = bos.toByteArray();
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream bais = new ByteArrayInputStream(body);
            return new ServletInputStream() {

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener listener) {
                    //不支持监听操作....
                    throw new UnsupportedOperationException();
                }

                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
    }
}
